// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_TASK_SCHEDULER_SCHEDULER_LOCK_H
#define BASE_TASK_SCHEDULER_SCHEDULER_LOCK_H

#include <memory>

#include "base/base_export.h"
#include "base/macros.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/task_scheduler/scheduler_lock_impl.h"

namespace base {
namespace internal {

    // SchedulerLock should be used anywhere a lock would be used in the scheduler.
    // When DCHECK_IS_ON(), lock checking occurs. Otherwise, SchedulerLock is
    // equivalent to base::Lock.
    //
    // The shape of SchedulerLock is as follows:
    // SchedulerLock()
    //     Default constructor, no predecessor lock.
    //     DCHECKs
    //         On Acquisition if any scheduler lock is acquired on this thread.
    //
    // SchedulerLock(const SchedulerLock* predecessor)
    //     Constructor that specifies an allowed predecessor for that lock.
    //     DCHECKs
    //         On Construction if |predecessor| forms a predecessor lock cycle.
    //         On Acquisition if the previous lock acquired on the thread is not
    //             |predecessor|. Okay if there was no previous lock acquired.
    //
    // void Acquire()
    //     Acquires the lock.
    //
    // void Release()
    //     Releases the lock.
    //
    // void AssertAcquired().
    //     DCHECKs if the lock is not acquired.
    //
    // std::unique_ptr<ConditionVariable> CreateConditionVariable()
    //     Creates a condition variable using this as a lock.

#if DCHECK_IS_ON()
    class SchedulerLock : public SchedulerLockImpl {
    public:
        SchedulerLock() = default;
        explicit SchedulerLock(const SchedulerLock* predecessor)
            : SchedulerLockImpl(predecessor)
        {
        }
    };
#else // DCHECK_IS_ON()
    class SchedulerLock : public Lock {
    public:
        SchedulerLock() = default;
        explicit SchedulerLock(const SchedulerLock*) { }

        std::unique_ptr<ConditionVariable> CreateConditionVariable()
        {
            return std::unique_ptr<ConditionVariable>(new ConditionVariable(this));
        }
    };
#endif // DCHECK_IS_ON()

    // Provides the same functionality as base::AutoLock for SchedulerLock.
    class AutoSchedulerLock {
    public:
        explicit AutoSchedulerLock(SchedulerLock& lock)
            : lock_(lock)
        {
            lock_.Acquire();
        }

        ~AutoSchedulerLock()
        {
            lock_.AssertAcquired();
            lock_.Release();
        }

    private:
        SchedulerLock& lock_;

        DISALLOW_COPY_AND_ASSIGN(AutoSchedulerLock);
    };

} // namespace internal
} // namespace base

#endif // BASE_TASK_SCHEDULER_SCHEDULER_LOCK_H
